package oc.tm.sg.core.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import oc.tm.sg.core.Constants;

public class StringUtils {
	
	private static final Pattern KVP_PATTERN = Pattern.compile("([_.a-zA-Z0-9][-_.a-zA-Z0-9]*)[=](.*)"); //key value pair pattern.
	
	/**
	 * 字符串转换为整数，如果为空，返回给定的默认值.
	 * @param str 待转换的字符串
	 * @param defVal 默认值
	 * @return int值
	 */
	public static int parseInt(String str, int defVal){
		try {
			if(isBlank(str)) return defVal;
			return Integer.parseInt(str);
		} catch (NumberFormatException e) {
			return defVal;
		}
	}
	
	public static boolean isNotBlank(String str){
		return !isBlank(str);
	}
	
	/**
	 * 判断字符串是否为空或者长度为0.
	 * @param str
	 */
	public static boolean isBlank(String str){
		return str == null || str.trim().length() == 0;
	}
	
	/**
	 * 判断字符串是否为空.
	 */
	public static boolean isEmpty(String str){
		return str==null || "".equals(str.trim());
	}

    /**
     * 判断给定对象是否为"空"或"空白".
     * 
     * @param obj
     *        对象
     * @param trim
     *        是否截除字符串后空格
     * @return <ul>
     *         <li><tt>true</tt> 如果对象为null.
     *         <li><tt>true</tt> 如果对象是空(0长度)字符串.
     *         <li><tt>true</tt> 如果对象是数组或集合，但个数为0.
     *         <li><tt>true</tt> 如果对象是数组或集合，且其中的每个元素都是"空"或"空白".
     *         <li><tt>true</tt> 如果对象是Map，返回Map.isEmpty().
     *         <li><tt>false</tt> 其它情况.
     *         </ul>
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
	public static boolean isEmptyOrBlank(Object obj, boolean trim) {
        if (obj == null)
            return true;
        if (obj instanceof String) {
            String ss = (String) obj;
            return (trim ? ss.trim() : ss).length() == 0;
        }
        if (obj instanceof Object[]) {
            Object[] oo = (Object[]) obj;
            for (int i = 0; i < oo.length; i++)
                if (!isEmptyOrBlank(oo[i], trim))
                    return false;
            return true;
        }
        if (obj instanceof Collection) {
            Collection<Object> oo = (Collection<Object>) obj;
            for (Iterator<Object> i = oo.iterator(); i.hasNext();)
                if (!isEmptyOrBlank(i.next(), trim))
                    return false;
            return true;
        }
        if (obj instanceof Map) {
            return ((Map) obj).isEmpty();
        }
        return false;
    }
    
	/**
	 * 判断两个字符串是否相等（两者都为null也相等）
	 */
	public static boolean isEquals(String s1, String s2) {
        if (s1 == null && s2 == null)
            return true;
        if (s1 == null || s2 == null)
            return false;
        return s1.equals(s2);
    }
	
	/**
	 * 用指定的分隔符把给定的数组里的值隔开最后组成一个字符串
	 * @param array 字符串数组
	 * @param seperator 分隔符
	 */
	public static String conc(String[] array, String seperator){
		String rst = "";
		for(int i=0; i<array.length; i++){
			if(i>0)
				rst += seperator;
			rst += array[i];
		}
		return rst;
	}

	/**
	 * 取值，若值为空，则返回默认值
	 */
	public static String getValue(String value, String defValue) {
		if (value == null || "".equals(value))
			return defValue;
		return value;
	}

	/**
	 * 字符串填充操作.（默认gb2312字符集)
	 * @param rs 源字符串
	 * @param ch 用于填充的字符，字符只能是可见字符
	 * @param num 目标字符串字节数组长度
	 * @param left 左填充还是右填充
	 * @return 补全后的字符串
	 */
	public static String fillChar(String rs, char ch, int num, boolean left) {
		int rsLen;
		try {
			rsLen = rs.getBytes(Constants.DEFAULT_ENCODING).length;
		} catch (UnsupportedEncodingException e) {
			throw new IllegalArgumentException(e);
		}
		
		StringBuilder sb = new StringBuilder();
		// 左补全
		if (left) {
			if (num >= rsLen) {
				for (int i = 0; i < num - rsLen; i++) {
					sb.append(ch);
				}
				sb.append(rs);
			} else
				sb.append(rs.substring(0, num));
		} else {
			if (num >= rsLen) {
				sb.append(rs);
				for (int i = 0; i < num - rsLen; i++) {
					sb.append(ch);
				}
			} else
				sb.append(rs.substring(0, num));
		}
		return sb.toString();
	}
	
	/**
	 * 删除字串的填充字符
	 * @param rs 源字符串
	 * @param ch 用于填充的字符，字符只能是可见字符
	 * @param left true为左填充，false为右填充
	 * @return 删除后的字符串
	 */
	public static String removeFillChar(String rs, char ch, boolean left) {
		if (left) {
			if (rs.charAt(0) != ch) return rs;
			int idx = rs.length();
			for (int i = 0; i < rs.length(); i++) {
				if (rs.charAt(i) != ch) {
					idx = i;
					break;
				}
			}
			return rs.substring(idx);
		} else {
			if (rs.charAt(rs.length()-1) != ch) return rs;
			int idx = -1;
			for (int i = rs.length() - 1; i >= 0; i--) {
				if (rs.charAt(i) != ch) {
					idx = i;
					break;
				}
			}
			return rs.substring(0, idx + 1);
		}
	}
	
	/**
	 * 去掉字符串的左边空格
	 */
	public static String ltrim(String s) {
		int len = s.length();
		int st = 0;
		char[] val = s.toCharArray();

		while ((st < len) && (val[st] <= ' ')) {
		    st++;
		}
		return (st > 0) ? s.substring(st, len) : s;
	}
	
	/**
	 * 去掉字符串的右边空格
	 */
	public static String rtrim(String s) {
		int len = s.length();
		int st = 0;
		char[] val = s.toCharArray();

		while ((st < len) && (val[len - 1] <= ' ')) {
		    len--;
		}
		return (len < s.length()) ? s.substring(st, len) : s;
	}
	
	/**
	 * 判断字符串是否符合给定的正则表达式.
	 * @param regex 正则表达式字符串
	 */
	public static boolean patternMatches(String regex, String str){
		if(str == null) return false;
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(str);
		return m.matches();
	}
	
	/**
	 * 判断字符串是否是以字母、数字、下划线开头的字符串.
	 */
	public static boolean isValidVariableName(String name){
		return StringUtils.isEmpty(name) ? false : patternMatches("^[a-zA-Z_]+\\w*$", name);
	}
	
	/**
	 * 判断字符串是否是以字母或者下划线开头，可以包含.和[]
	 */
	public static boolean isValidLeftOperator(String name){
		return StringUtils.isEmpty(name) ? false : patternMatches("^[a-zA-Z_]+(\\.?\\w+(\\[\\d+\\])*)*$", name);
	}
	
	/**
	 * 判断字符串是否包含给定的字符串正则表达式
	 */
	public static boolean startsWith(String str, String regexp){
		return Pattern.compile(regexp).matcher(str).find();
	}

	public static String repeat(String str, int times){
		String r = "";
		for(int i=0; i<times; i++)
			r += str;
		return r;
	}

	
	/**
	 * 右填充ASCii字符串，一个汉字按两个字符算
	 * @param str
	 * @param length
	 * @param padding
	 * @return
	 */
	public static String asciiPaddingR(String str, int length, String padding){
		String rst = asciiTrimR(str, length);
		int alen = asciiLength(rst);
		if(alen == length)
			return rst;
		rst += repeat(padding, (length-alen)/asciiLength(padding));
		return rst;
	}
	
	/**
	 * 右修剪ASCii字符串，一个汉字按两个字符算
	 * @param str
	 * @param length
	 * @return
	 */
	public static String asciiTrimR(String str, int length){
		int alen = asciiLength(str);
		if(alen <= length)
			return str;
		String result = "";
		alen = 0;
		for(int i=0; i< length; i++){
			char c = str.charAt(i);
			alen += c >127 ? 2 : 1;
			if(alen <= length)
				result += c;
			else
				break;
		}
		return result;
	}
	
	/**
	 * ASCii字符串长度，一个汉字按两个字符算
	 * @param str
	 * @return
	 */
	public static int asciiLength(String str){
		int length = 0;
		for(int i=0; i<str.length();i++){
			char c = str.charAt(i);
			length += c > 127 ? 2 : 1;
		}
		
		return length;
	}	
	
	/**
	 * ascii位置转字串位置
	 * @param str
	 * @param asciiIdx
	 * @return
	 */
	public static int asciiIdx2StrIdx(String str, int asciiIdx){
		int length = 0;
		for(int i=0; i<str.length();i++){
			char c = str.charAt(i);
			length += c > 127 ? 2 : 1;
			if(length >= asciiIdx)
				return i;
		}
		
		return -1;
	}

	/**
	 * 填充SCii字符串，一个汉字按两个字符算
	 * @param str
	 * @param startIdx, index from 0
	 * @param fillStr
	 * @return
	 */
	public static String asciiFill(String str, int startIdx, String fillStr){
		String charset = Constants.DEFAULT_ENCODING;
		try {
			byte[] bs = str.getBytes(charset);
			byte[] fb = fillStr.getBytes(charset);
			int capacity = bs.length;
			if(startIdx + fb.length > bs.length)
				capacity = startIdx+fb.length;
			ByteBuffer bb = ByteBuffer.allocate(capacity);
			bb.put(bs);
			if(startIdx > bs.length){
				for(int i = startIdx - bs.length; i > 0; i--){
					bb.put((byte)0x20);
				}
			}

			boolean isChiChar=false;
			boolean isChiCharBegin=false;
			int fillLastIdx = startIdx + fb.length;
			for(int i=0;i<bs.length&&fillLastIdx>0;i++){
				if(bb.get(i)>=0){
					isChiChar = false;
					isChiCharBegin = false;
				}else{
					isChiChar = true;
					isChiCharBegin = i==0?true:!isChiCharBegin;
				}
				if(i == startIdx){
					if(isChiChar && !isChiCharBegin){
						bb.put(i-1, (byte)0x20);
						bb.put(i, (byte)0x20);
					}
				}else if(i == fillLastIdx){
					if(isChiChar && !isChiCharBegin){
						bb.put(i-1, (byte)0x20);
						bb.put(i, (byte)0x20);
					}
					break;
				}
			
			}
			
			bb.position(startIdx);
			bb.put(fb);
			return new String(bb.array(), charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	/**
	 * 填充SCii字符串，一个汉字按两个字符算
	 * @param str
	 * @param startIdx, index from 0
	 * @param fillStr
	 * @return
	 */
	public static String asciiFill2(String str, int startIdx, String fillStr){
		int idx = asciiIdx2StrIdx(str, startIdx);
		String ret = "";
		if(idx == -1){
			ret = asciiPaddingR(str, startIdx, " ");
			ret += fillStr;
		}else{
			ret = str.substring(0, idx)+fillStr;
			if(ret.length()<str.length())
				ret += str.substring(ret.length()); 
		}
		return ret;	
	}
	
	

	public static String hexChars2Str(String delimChar){
		if(delimChar.matches("(0[x,X](-){0,1}[0-9,a-f,A-F]+)+")){
			String[] ss = delimChar.split("0[x,X]");
			byte[] bs = new byte[ss.length -1 ];
			for(int i=1; i<ss.length; i++){
				
				byte b = (byte)Integer.parseInt(ss[i], 16);
				bs[i-1] = b;
				
			}
			return  new String(bs);
		}
		return delimChar;
		
	}
	
	/**
     * 将查询字符串解析成参数
     * 
     * @param qs 查询串
     * @return 参数实例
     */
	public static Map<String, String> parseQueryString(String qs)
	{
	    if( qs == null || qs.length() == 0 )
            return new HashMap<String, String>();
	    return parseKeyValuePair(qs, "\\&");
	}
	/**
	 * 解析key-value对
	 * 
	 * @param str 字符串
	 * @param itemSeparator 分隔符
	 * @return key-value map
	 */
	private static Map<String, String> parseKeyValuePair(String str, String itemSeparator)
	{
		String[] tmp = str.split(itemSeparator);
		Map<String, String> map = new HashMap<String, String>(tmp.length);
		for(int i=0;i<tmp.length;i++)
		{
			Matcher matcher = KVP_PATTERN.matcher(tmp[i]);
			if( matcher.matches() == false )
				continue;
			map.put(matcher.group(1), matcher.group(2));
		}
		return map;
	}
	
	/**
     * 将属性转换为查询串
     */
	public static String toQueryString(Map<String, String> ps) {
		StringBuilder buf = new StringBuilder();
		if (ps != null && ps.size() > 0) {
			for (Map.Entry<String, String> entry : new TreeMap<String, String>(ps).entrySet()) {
				String key = entry.getKey();
				String value = entry.getValue();
				if (key != null && key.length() > 0
						&& value != null && value.length() > 0) {
					if (buf.length() > 0) {
						buf.append("&");
					}
					buf.append(key);
					buf.append("=");
					buf.append(value);
				}
			}
		}
		return buf.toString();
	}
	
	/**
	 * 获取字符串对应的字节内容（默认GB2312字符集）
	 */
	public static byte [] getBytes(String s) {
		try {
			return s.getBytes(Constants.DEFAULT_ENCODING);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
     * 分割多行字符串到字符串数组.
     * <p>
     * 即分融符为：换行，或回车加换行.
     * 
     * @param str
     *        待分割字符串
     * @return an array of lines that comprise the string, or null if the string specified was null
     */
    public static String[] splitIntoLines(String str) {
        if (str == null)
            return null;
        BufferedReader br = new BufferedReader(new StringReader(str));

        ArrayList<String> linesList = new ArrayList<String>();

        try {
            String line = br.readLine();
            while (line != null) {
                linesList.add(line);
                line = br.readLine();
            }
        } catch (IOException notGoingToHappenWithAnInMemoryStringReaderEx) {
        }

        return (String[]) linesList.toArray(new String[linesList.size()]);
    }

    /**
     * 分割字符串(用单个字符). 不使用正则表达式，提高性能。
     * 
     * @param s
     *        待分割字符串
     * @param delimiter
     *        分融符
     * @param trim
     *        是否截去前后空格
     * @return List
     *         <ul>
     *         <li><tt>空列表</tt> 如果对象为null.
     *         <li><tt>含一个空字符串的列表</tt> 如果对象是空字符串.
     *         </ul>
     */
    public static List<String> split(String s, char delimiter, boolean trim) {
        List<String> ret = new ArrayList<String>();
        if (s == null) {
            return ret;
        }
        int lastIdx = 0;
        int idx = s.indexOf(delimiter);

        while (idx > 0) {
            String s1 = s.substring(lastIdx, idx);
            if (trim)
                s1 = s1.trim();
            ret.add(s1);

            lastIdx = idx + 1;
            idx = s.indexOf(delimiter, lastIdx);
        }

        String s1 = s.substring(lastIdx);
        if (trim)
            s1 = s1.trim();
        ret.add(s1);

        return ret;
    }

    /**
     * 分割字符串(用单个字符)并截去前后空格. 不使用正则表达式，提高性能。 相当于<code>split(s, delimiter, true)</code>的快捷方式.
     * <table border="1">
     * <tr>
     * <td><strong>源串</strong></td>
     * <td><strong>结果</strong></td>
     * </tr>
     * <tr>
     * <td>a,&nbsp;,&nbsp;&nbsp;,,&nbsp;b</td>
     * <td>[a,,,,b]</td>
     * </tr>
     * <tr>
     * <td>a,b&nbsp;&nbsp;&nbsp;c&nbsp;,d</td>
     * <td>[a,b&nbsp;&nbsp;&nbsp;c,d]</td>
     * </tr>
     * </table>
     * 
     * @param s
     *        待分割字符串
     * @param delimiter
     *        分融符
     * @param trim
     *        是否截去前后空格
     * @return List
     *         <ul>
     *         <li><tt>空列表</tt> 如果对象为null.
     *         <li><tt>含一个空字符串的列表</tt> 如果对象是空字符串或全空格字符串.
     *         </ul>
     */
    public static List<String> split(String s, char delimiter) {
        return split(s, delimiter, true);
    }

    /**
     * 按空白字符(空格)或逗号分隔字符串. 本方法的返回结果中不包括零长字符串，示例如下：
     * <table border="1">
     * <tr>
     * <td><strong>源串</strong></td>
     * <td><strong>结果</strong></td>
     * </tr>
     * <tr>
     * <td>a,,,,b</td>
     * <td>[a, b]</td>
     * </tr>
     * <tr>
     * <td>a,b&nbsp;&nbsp;&nbsp;c,d</td>
     * <td>[a, b, c, d]</td>
     * </tr>
     * </table>
     * <b>使用了正则表达式，注意性能问题，不能在调用频繁度的地方使用</b>
     * 
     * @param input
     *        源串
     * @return 字符串列表. <tt>null</tt> 如果源串为null
     */
    public static List<String> split(String input) {
        return split(input, "[\\s,]+");
    }

    /**
     * 使用指定的正则表达式分隔字符串. 本方法的返回结果中不包括零长字符串（这是与String.split方法的不同之处）
     * 
     * @param input
     *        源串
     * @param sep
     *        正则表达式
     * @return 字符串列表. <tt>null</tt> 如果源串为null
     */
    public static List<String> split(String input, String sep) {
        if (input == null)
            return null;
        int index = 0;
        List<String> matchList = new ArrayList<String>();
        Matcher m = Pattern.compile(sep).matcher(input);

        // Add segments before each match found
        while (m.find()) {
            if (index < m.start()) {
                String match = input.subSequence(index, m.start()).toString();
                matchList.add(match);
            }
            index = m.end();
        }

        if (index < input.length())
            matchList.add(input.subSequence(index, input.length()).toString());

        return matchList;
    }

    /**
     * 判断value字符串是否在values列表中
     * @param values
     * @param value
     * @return
     */
    public static boolean isContains(String values, String value) {
        if (values == null || values.length() == 0) {
            return false;
        }
        return isContains(Constants.COMMA_SPLIT_PATTERN.split(values), value);
    }
    
    /**
     * @param values
     * @param value
     * @return contains
     */
    public static boolean isContains(String[] values, String value) {
        if (value != null && value.length() > 0 && values != null && values.length > 0) {
            for (String v : values) {
                if (value.equals(v)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 将第一个字母大写,其它不变
     * 
     * @param name
     * @return
     */
    public static String capitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        return new String(chars);
    }

    /**
     * 将第一个字母小写,其它不变
     * 
     * @param name
     * @return
     */
    public static String unCapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }
}
